<!-- 我的全选树形下拉框 -->
<template>
  <el-cascader class="my-all-cascader"
    v-model="nowData"
    :options="treeOptions"
    :props="props"
    :size="size"
    collapse-tags
    :clearable="clearable"
    @change="change">
    <template slot-scope="scope">
      <div v-if="scope.data.isAll" class="all-btn" @click="toggleAll(scope.data.keys)">
        {{scope.data[label]}}
      </div>
      <template v-else>
        {{scope.data[label]}}
      </template>
    </template>  
  </el-cascader>
</template>
<script>
export default {
  data () {
    return {
      nowData: [], // 选中的值
    }
  },
  model: {
    prop: 'data',
    event: 'data-change'
  },
  props: {
    // 数据
    data: {
      default () {
        return []
      }
    },
    tree: {
      default () {
        return []
      }
    },

    // 配置项
    label: {
      default: 'label'
    },
    value: {
      default: 'value'
    },
    children: {
      default: 'children'
    },
    // 是否简单的值 - 如果设为false，将返回原本组件的值
    simpleData: {
      default: true
    },
    size: {
      default: ''
    },
    clearable: {
      default: false
    }
  },
  computed: {
    // 添加全选后的树
    treeOptions () {
      return this.addAllItme(this.tree);
    },
    // 下拉框的配置
    props () {
      return {
        multiple: true, // 多选
        checkStrictly: true, // 父子不关联
        label: this.label,
        value: this.value,
        children: this.children
      }
    },
  },
  watch: {
    data (newVal) {
      this.setNowData();
    }
  },
  mounted () {
    this.setNowData();
  },
  methods: {
    // 当前的值
    setNowData () {
      if (JSON.stringify(this.data) == JSON.stringify(this.nowData)) {
        return false;
      }
      var _this = this, res = [];
      if (this.simpleData) {
        ergodic(this.tree);
        // 遍历
        function ergodic (arr, pVal = []) {
          for (var i = 0; i < arr.length; i++) {
            var item = arr[i];
            var val = item[_this.value], children = item[_this.children], tVal = [...pVal, val];
            if (_this.data.indexOf(val) != -1) {
              res.push(tVal);
            }
            if (children && children.length) {
              ergodic(children, tVal);
            }
          }
        }
      } else {
        res = JSON.parse(JSON.stringify(this.data));
      }
      this.nowData = res;
    },

    // 添加全选按钮
    addAllItme (tree) {
      var _this = this;
      tree = JSON.parse(JSON.stringify(tree));
      ergodic(tree);
      return tree;
      function ergodic (arr, pVal = '') {
        for (var i = 0; i < arr.length; i++) {
          var item = arr[i];
          var value = item[_this.value], children = item[_this.children];
          if (children && children.length) {
            ergodic(children, item.value);
          }
        }
        // 添加全选按钮
        var allObj = {
          isAll: true, // 是全选按钮
          keys: arr.map(item => item[_this.value]), // 当前一级的所有值
        }
        allObj[_this.label] = '全选';
        allObj[_this.value] = '_all_' + pVal;
        arr.unshift(allObj);
      }
    },

    // 切换全部
    toggleAll (keys) {
      var aAdd = this.getNeedAdd(keys);
      
      // 表示需要添加 - 为空表示删除
      if (aAdd.length) {
        this.nowData = [...this.nowData, ...aAdd];
      } else {
        // 判断value不在keys时，添加到aData中
        var aData = [];
        this.nowData.forEach((item,index) => {
          var val = item[item.length - 1];
          // 当前值不在keys中
          if (keys.indexOf(val) == -1) {
            aData.push(item);
          }
        })
        this.nowData = aData;
      }
      // 更新值
      this.change(this.nowData);
    },

    // 获取需要添加的结点
    getNeedAdd (keys) {
      var _this = this;
      var res = [], aKey = [];

      keys.forEach((aItem, aIdx) => {
        var i = 0;
        for (;i < this.nowData.length; i++) {
          var bItem = this.nowData[i];
          if (aItem == bItem[bItem.length - 1]) {
            break;
          }
        }
        if (i >= this.nowData.length) {
          aKey.push(aItem);
        }
      })

      // 递归 设置 返回值
      ergodic(this.tree);
      function ergodic (arr, pVal = []) {
        for (var i = 0; i < arr.length; i++) {
          var item = arr[i];
          var val = item[_this.value], children = item[_this.children], tVal = [...pVal, val];
          if (aKey.indexOf(val) != -1) {
            res.push(tVal);
          }
          if (children && children.length) {
            ergodic(children, tVal);
          }
        }
      }

      return res;
    },

    change (val) {
      var res = [];
      if (this.simpleData) {
        val.forEach(item => {
          res.push(item[item.length - 1]);
        })
      } else {
        res = val;
      }
      this.$emit('data-change', res);
    }
  }
}
</script>
<style lang="scss" scoped>
.all-btn {
  position: absolute;
  z-index: 2;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  padding-left: 44px;
  background: #fff;
  box-sizing: border-box;
  &:hover {
    background: #F5F7FA;
  }
}

</style>
<style lang="scss">
.el-cascader.el-cascader--mini {
  .el-tag--info {
    max-width: calc(100% - 50px);
  }
  .el-input.el-input--mini input {
    height: 28px !important;
  }
}
</style>

